package datastore.db.polymodel;

public class Polymodel {
/*
It is often useful to define data models as a classification hierarchy, much like how an object database can define one class of objects as a sub-class of another. Such a database can perform queries on objects of the parent class, and include objects of the sub-class in the results. The App Engine datastore does not support this kind of query natively, but you can implement it using a mechanism included with the Python SDK, the PolyModel class.

A model class derived from PolyModel can be the base class for other model classes. Queries created for these classes using the all() and gql() methods know to include instances of subclasses in the results.

Subclasses can define new properties not present on parent classes. However, subclasses cannot override property definitions of parent classes. (Doing so results in a DuplicateProperty error.)

For reference, here is the simple example from Entities and Models. Notice that the PolyModel class is provided by the package google.appengine.ext.db.polymodel.

from google.appengine.ext import db
from google.appengine.ext.db import polymodel

class Contact(polymodel.PolyModel):
  phone_number = db.PhoneNumberProperty()
  address = db.PostalAddressProperty()

class Person(Contact):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  mobile_number = db.PhoneNumberProperty()

class Company(Contact):
  name = db.StringProperty()
  fax_number = db.PhoneNumberProperty()

p = Person(phone_number='1-206-555-9234',
           address='123 First Ave., Seattle, WA, 98101',
           first_name='Alfred',
           last_name='Smith',
           mobile_number='1-206-555-0117')
p.put()

c = Company(phone_number='1-503-555-9123',
            address='P.O. Box 98765, Salem, OR, 97301',
            name='Data Solutions, LLC',
            fax_number='1-503-555-6622')
c.put()

for contact in Contact.all():
  # Returns both p and c.
  # ...

for person in Person.all():
  # Returns only p.
  # ...

PolyModel does not support dynamic properties, like Expando does. There is not an equivalent of PolyModel for Expando.

Polymorphism is not a native feature of the datastore. Instead, polymorphism is implemented in the PolyModel class itself. All entities created from PolyModel subclasses are stored in the datastore with the same kind, which is the name of the root class (e.g. Animal). Each object stores its class hierarchy as a multi-valued property of the entity named 'class'. When the app creates a query using a PolyModel class's all() or gql() method, the query includes a filter on the 'class' property that limits the results to entities created from the class or any subclass.

Because PolyModel uses a property of the entity to store class information, indexes for polymorphic queries must accommodate the 'class' property. The implied filter is an equality filter, and can be combined with other equality filters and inequality filters on other properties.

Note: PolyModel uses just the names of the classes in the 'class' property, not full paths. It's possible to create class hierarchies with multiple nodes of the same name, such as A → B and A → C → B. A query for one will return entities of both. Similarly, queries for A → B → C and A → C → B are functionally identical. It's best to avoid creating a single class hierarchy with multiple nodes of the same name.
Constructor

The constructor of the PolyModel class is defined as follows:

class PolyModel(parent=None, key_name=None, **kw)

    A model class that can be a superclass to other model classes, and whose queries can include instances of subclasses as results. Like Model, the PolyModel class must be subclassed to define the kind of the data entities.

    PolyModel is a subclass of Model, and inherits or overrides its methods.

    Arguments:

    parent
        The Model instance or Key instance for the entity that is the new entity's parent.
    key_name

        The name for the new entity. The name becomes part of the primary key. If None, a system-generated ID is used for the key.

        The value for key_name must not start with a number, and must not be of the form __*__. If your application uses user-submitted data as datastore entity key names (such as an email address), the application should sanitize the value first, such as by prefixing it with a known string like "key:", to meet these requirements.

        A key_name is stored as a Unicode string, with str values converted as ASCII text.
    **kw
        Initial values for the instance's properties, as keyword arguments. Each name corresponds with an attribute of the new instance, and must correspond with fixed properties defined in the PolyModel class.

Class Methods

In addition to the class methods defined by the Model class, the PolyModel class provides the following class methods:

PolyModel.class_key()

    Returns the name of the class and the names of all parent classes for the class, as a tuple.
PolyModel.class_name()

    Returns the name of the class. A class can override this method if the name of the Python class changes, but entities should continue using the original class name.

 */
}
